﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using AgilePlannerDT.Data;

namespace AgilePlannerDT.ThirdPartySync
{
    public enum Priority
    {
        AgilePlanner,
        Server
    }


    public class Sync
    {
        Project agilePlannerProject;

        public Sync(Project proj)
        {
            this.agilePlannerProject = proj;
        }

        public void syncronize(ISyncronizer syncronizer, Priority priority)
        {
            try
            {
                syncronizeIterations(syncronizer, priority);
                syncronizeStoryCards(syncronizer, priority);
            }catch(Exception e){
                return;
            }
        }

        private void syncronizeIterations(ISyncronizer syncronizer, Priority priority)
        {
            List<Iteration> foriegn = syncronizer.getActiveIterations();
            List<Iteration> local = agilePlannerProject.IterationChildren;

            List<Iteration> toCreate;
            List<Iteration> toDelete;
            List<Iteration> localLeftOver = new List<Iteration>();
            List<Pair<Iteration>> toUpdate = new List<Pair<Iteration>>();
            Boolean matched = false;
            for (int l = 0; l < local.Count(); l++)
            {
                for (int f = 0; f < foriegn.Count(); f++)
                {
                    if ( foriegn[f].SyncID.Equals(local[l].SyncID) )
                    {
                        toUpdate.Add(new Pair<Iteration>(local[l], foriegn[f]));
                        foriegn.RemoveAt(f);
                        matched = true;
                        break;
                    }
                }
                if (!matched)
                {
                    localLeftOver.Add(local[l]);
                }
                matched = false;
            }
            if (priority.Equals(Priority.AgilePlanner))
            {
                toCreate = localLeftOver;
                toDelete = foriegn;
            }
            else
            {
                toDelete = localLeftOver;
                toCreate = foriegn;
            }
            doIterSync(syncronizer, priority, toCreate, toUpdate, toDelete);
        }

        private void doIterSync(ISyncronizer syncronizer, Priority priority, List<Iteration> toCreate, List<Pair<Iteration>> toUpdate, List<Iteration> toDelete)
        {
            if (priority.Equals(Priority.AgilePlanner))
            {
                foreach (Pair<Iteration> iter in toUpdate) syncronizer.updateTimeBox(iter.Local);
                foreach (Iteration iter in toCreate) syncronizer.createTimeBox(iter);
                foreach (Iteration iter in toDelete) syncronizer.deleteTimeBox(iter);
            }
            else
            {
                foreach (Pair<Iteration> iter in toUpdate) syncronizer.updateIteration(iter.Local);
                foreach (Iteration iter in toCreate) agilePlannerProject.CreateIteration(iter);
                foreach (Iteration iter in toDelete) agilePlannerProject.DeleteCard(iter.ID);
            }
        }

        private void syncronizeStoryCards(ISyncronizer syncronizer, Priority priority)
        {
            List<StoryCard> foriegn = syncronizer.getActiveWorkItems();
            List<StoryCard> local = new List<StoryCard>();
            local.AddRange(agilePlannerProject.Backlog.StoryCardChildren);
            foreach(Iteration iter in agilePlannerProject.IterationChildren)
                local.AddRange(iter.StoryCardChildren);

            List<StoryCard> toCreate;
            List<StoryCard> toDelete;
            List<StoryCard> localLeftOver = new List<StoryCard>();
            List<Pair<StoryCard>> toUpdate = new List<Pair<StoryCard>>();
            Boolean matched = false;
            for (int l = 0; l < local.Count(); l++)
            {
                for (int f = 0; f < foriegn.Count(); f++)
                {
                    if (foriegn[f].SyncID.Equals(local[l].SyncID))
                    {
                        toUpdate.Add(new Pair<StoryCard>(local[l], foriegn[f]));
                        foriegn.RemoveAt(f);
                        matched = true;
                        break;
                    }
                }
                if (!matched)
                {
                    localLeftOver.Add(local[l]);
                }
                matched = false;
            }
            if (priority.Equals(Priority.AgilePlanner))
            {
                toCreate = localLeftOver;
                toDelete = foriegn;
            }
            else
            {
                toDelete = localLeftOver;
                toCreate = foriegn;
            }
            doStorySync(syncronizer, priority, toCreate, toUpdate, toDelete);
        }

        private void doStorySync(ISyncronizer syncronizer, Priority priority, List<StoryCard> toCreate, List<Pair<StoryCard>> toUpdate, List<StoryCard> toDelete)
        {
            if (priority.Equals(Priority.AgilePlanner))
            {
                foreach (Pair<StoryCard> card in toUpdate) 
                    syncronizer.updateWorkItem(card.Local);
                foreach (StoryCard card in toCreate) 
                    syncronizer.createWorkItem(card);
                foreach (StoryCard card in toDelete) 
                    syncronizer.deleteWorkItem(card);
            }
            else
            {
                foreach (Pair<StoryCard> card in toUpdate) 
                    syncronizer.updateStoryCard(card.Local);
                foreach (StoryCard card in toCreate) 
                    agilePlannerProject.CreateStoryCard(card);
                foreach (StoryCard card in toDelete) 
                    agilePlannerProject.DeleteCard(card.ID);
            }
        }

    }

    class Pair<T>
    {
        public T Local { get; private set; }
        public T Foriegn { get; private set; }

        public Pair(T local, T foriegn)
        {
            Local = local;
            Foriegn = foriegn;
        }
    }
}

